package com.magiccompass.alipay.barcode.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

import com.magiccompass.alipay.barcode.common.DicInit;
import com.magiccompass.alipay.barcode.constants.BusinessLogicConstants;
import com.magiccompass.alipay.barcode.entity.MerchantEmails;
import com.magiccompass.alipay.barcode.entity.MerchantInfo;
import com.magiccompass.alipay.barcode.entity.MerchantTransaction;
import com.magiccompass.alipay.barcode.model.DailySettlementEmailModel;
import com.magiccompass.alipay.barcode.model.DailySettlementRecordModel;
import com.magiccompass.alipay.barcode.service.MerchantBusinessService;

@Component
public class DailySettlementFileHandler {
	private static DailySettlementFileHandler singleton = new DailySettlementFileHandler();
	private DailySettlementFileHandler(){}
	public static DailySettlementFileHandler getInstance(){
		return singleton;
	}
	
	private static final String DAILY_SETTLEMENT_FILE_ROOT_PATH = "d:/alipay_barcode_daily_settlement_file/";
	
	private List<DailySettlementRecordModel> dailySettlementRecordsAdmin = new ArrayList<DailySettlementRecordModel>();
	private List<DailySettlementRecordModel> dailySettlementRecordsSingleMerchant = new ArrayList<DailySettlementRecordModel>();
	
	// I've no idea why @Resource(name="merchantBusinessService") not working here.
	private MerchantBusinessService merchantBusinessService;
	
	public void startMakeDailySettlementFile(){
		dailySettlementRecordsAdmin = new ArrayList<DailySettlementRecordModel>();
		makeRecordsFromDB();
		makeReportFile(dailySettlementRecordsAdmin,null,"admin");
	}
	
	private void makeRecordsFromDB(){
		List<MerchantInfo> allActiveMerchant = merchantBusinessService.findAllActiveMerchant();
		Timestamp yesterdayStartTime = DateTimeUtil.getYesterdayStartTime();
		Timestamp yesterdayEndTime   = DateTimeUtil.getYesterdayEndTime();
		for(MerchantInfo aMerchant:allActiveMerchant){
			List<MerchantTransaction> singleMerchantYesterdayMTRecords = merchantBusinessService.getMerchantTransactionListWithAlipayStatusOnlyByUpdateTime(
					yesterdayStartTime.getTime(),yesterdayEndTime.getTime(), aMerchant.getId());
			if(singleMerchantYesterdayMTRecords != null && singleMerchantYesterdayMTRecords.size()>0){
				dailySettlementRecordsSingleMerchant = makeDailySettlementRecord(singleMerchantYesterdayMTRecords);
				makeReportFile(dailySettlementRecordsSingleMerchant,aMerchant,"merchant");
				dailySettlementRecordsAdmin.addAll(dailySettlementRecordsSingleMerchant);
			}
		}
	}
	private void makeReportFile(List<DailySettlementRecordModel> data, MerchantInfo mi, String reportType){
		if(data.size()>0){
			String fileName = "";
			String absoluteFileDirPath = "";
			if("merchant".equals(reportType)){
				fileName = mi.getMerchantName()+"_"+DateTimeUtil.getYesterdayYYYYMMDDString()+".csv";
				absoluteFileDirPath = getWriteToFilePath(reportType);
			}else{
				fileName = "Admin_"+DateTimeUtil.getYesterdayYYYYMMDDString()+".csv";
				absoluteFileDirPath = getWriteToFilePath(reportType);
			}
			File fileNewDir=new File(absoluteFileDirPath);
			if(!fileNewDir.exists()){
				fileNewDir.mkdirs();
			}
			File file = new File(absoluteFileDirPath+fileName);
			try(PrintWriter printWriter = new PrintWriter(file,"UTF-8")) {
				BigDecimal overallCollectionAmt = new BigDecimal(0);
				BigDecimal overallExpenditureAmt = new BigDecimal(0);
				BigDecimal overallRefundAmt = new BigDecimal(0);
				BigDecimal overallSettlementAmt = new BigDecimal(0);
				
				printWriter.println(makeHeaderLine());
				DailySettlementEmailModel dsem = new DailySettlementEmailModel();
				if("merchant".equals(reportType)){
					for(DailySettlementRecordModel aRecord:data){
						printWriter.println(makeDetailLine(aRecord));
						overallCollectionAmt = overallCollectionAmt.add(aRecord.getCollectionAmount());
						overallExpenditureAmt = overallExpenditureAmt.add(aRecord.getExpenditureAmount());
						overallRefundAmt = overallRefundAmt.add(aRecord.getRefundAmount());
						overallSettlementAmt = overallSettlementAmt.add(aRecord.getSettlementAmount());
					}
					printWriter.println(makeFooterLine(overallCollectionAmt,overallExpenditureAmt,overallRefundAmt,overallSettlementAmt));
					
					dsem.setReceiverEmailAddress(mi.getEmail());
					dsem.setReceiverName(mi.getMerchantName());
					List<MerchantEmails> merchantSupportEmails = merchantBusinessService.findAllActiveMerchantSupportEmails(mi.getId());
					if(!merchantSupportEmails.isEmpty()){
						List<String> ccEmailList = new ArrayList<String>();
						for(MerchantEmails aMerchantSupportEmail:merchantSupportEmails){
							ccEmailList.add(aMerchantSupportEmail.getEmailAddress());
						}
						dsem.setEmailCCList(ccEmailList);
					}
				}else{
					Integer currentMerchantId = 0;				
					for(DailySettlementRecordModel aRecord:data){
						if(currentMerchantId.intValue() == 0){
							currentMerchantId = aRecord.getMerchantId();
							printWriter.println(makeDetailLine(aRecord));
							overallCollectionAmt = aRecord.getCollectionAmount();
							overallExpenditureAmt = aRecord.getExpenditureAmount();
							overallRefundAmt = aRecord.getRefundAmount();
							overallSettlementAmt = aRecord.getSettlementAmount();
						}else if(currentMerchantId.intValue() != aRecord.getMerchantId().intValue()){
							printWriter.println(makeFooterLine(overallCollectionAmt,overallExpenditureAmt,overallRefundAmt,overallSettlementAmt));
							printWriter.println();
							printWriter.println(makeDetailLine(aRecord));
							overallCollectionAmt = aRecord.getCollectionAmount();
							overallExpenditureAmt = aRecord.getExpenditureAmount();
							overallRefundAmt = aRecord.getRefundAmount();
							overallSettlementAmt = aRecord.getSettlementAmount();
							currentMerchantId = aRecord.getMerchantId();
						}else{
							printWriter.println(makeDetailLine(aRecord));
							overallCollectionAmt = overallCollectionAmt.add(aRecord.getCollectionAmount());
							overallExpenditureAmt = overallExpenditureAmt.add(aRecord.getExpenditureAmount());
							overallRefundAmt = overallRefundAmt.add(aRecord.getRefundAmount());
							overallSettlementAmt = overallSettlementAmt.add(aRecord.getSettlementAmount());
						}
					}
					printWriter.println(makeFooterLine(overallCollectionAmt,overallExpenditureAmt,overallRefundAmt,overallSettlementAmt));
					
					dsem.setReceiverEmailAddress(BusinessLogicConstants.SYSTEM_ADMIN_EMAIL_ADDRESS);
					dsem.setReceiverName(BusinessLogicConstants.SYSTEM_ADMIN_NAME);
				}
				dsem.setEmailTitle(DateTimeUtil.getYesterdayYYYYMMDDString()+" settlement records");
				dsem.setEmailBodyMessage("Hi "+dsem.getReceiverName()+", Attachment is yesterday settlement records.");
				dsem.setReportFileAbsolutePath(absoluteFileDirPath+fileName);
				DailySettlementFileEmailHandler.dailySettlementEmailBatchList.add(dsem);		
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	private String makeHeaderLine(){
		StringBuffer sb = new StringBuffer();
		sb.append("Merchant Id,");
		sb.append("Merchant Name,");
		sb.append("Transaction Time,");
		sb.append("Type,");
		sb.append("Status,");
		sb.append("Partner_transaction_ID,");
		sb.append("Collection,");
		sb.append("Expenditure,");
		sb.append("Refund,");		
		sb.append("Settlement,");
		sb.append("Currency,");
		sb.append("Rate,");
		sb.append("Goods_title,");
		sb.append("Product");
		return sb.toString();
	}
	private String makeDetailLine(DailySettlementRecordModel aRow){
		StringBuffer sb = new StringBuffer();
		sb.append(aRow.getMerchantId()).append(",");
		sb.append(aRow.getMerchantName()).append(",");
		sb.append(aRow.getTransactionTime()).append(",");
		sb.append(aRow.getType()).append(",");
		sb.append(aRow.getStatus()).append(",");
		sb.append(aRow.getMtId()).append(",");
		sb.append(aRow.getCollectionAmount()).append(",");
		sb.append(aRow.getExpenditureAmount()).append(",");
		sb.append(aRow.getRefundAmount()).append(",");
		sb.append(aRow.getSettlementAmount()).append(",");		
		sb.append(aRow.getCurrency()).append(",");
		sb.append(aRow.getRate()).append(",");
		sb.append(aRow.getGoodsTitle()).append(",");
		sb.append(aRow.getProduct());
		return sb.toString();
	}
	private String makeFooterLine(BigDecimal overallCollectionAmt,BigDecimal overallExpenditureAmt,BigDecimal overallRefundAmt,BigDecimal overallSettlementAmt){
		StringBuffer sb = new StringBuffer();
		sb.append("Total,"); // merchant ID
		sb.append(","); // merchant name
		sb.append(","); // transaction time
		sb.append(","); // type
		sb.append(","); // status
		sb.append(","); // mt ID
		sb.append(overallCollectionAmt+","); // collection amount
		sb.append(overallExpenditureAmt+","); // expenditure amount
		sb.append(overallRefundAmt+","); // refund amount
		sb.append(overallSettlementAmt+","); // settlement amount
		sb.append(","); // currency
		sb.append(","); // rate
		sb.append(","); // goods title
		sb.append(","); // product
		return sb.toString();
	}
	private String getWriteToFilePath(String role){
		StringBuffer sb = new StringBuffer();
		sb.append(DAILY_SETTLEMENT_FILE_ROOT_PATH);
		Timestamp yesterdayTime = DateTimeUtil.getYesterdayStartTime();
		sb.append(DateTimeUtil.formatTimeByFormat(yesterdayTime,"yyyy/MM/dd"));
		if("admin".equals(role)){
			sb.append("/admin/");
		}else{
			sb.append("/merchant/");
		}
		return sb.toString();
	}
	
	private List<DailySettlementRecordModel> makeDailySettlementRecord(List<MerchantTransaction> mtList){
		List<DailySettlementRecordModel> returnList = new ArrayList<DailySettlementRecordModel>();
		DailySettlementRecordModel dsr;
		BigDecimal merchantFeeRate;
		BigDecimal merchantMutiplyRate;
		for(MerchantTransaction mt:mtList){
			dsr = new DailySettlementRecordModel();
			merchantFeeRate = mt.getMerchant().getFeeRate();
			dsr.setMerchantId(mt.getMerchant().getId());
			dsr.setMerchantName(mt.getMerchant().getMerchantName());
			dsr.setTransactionTime(DateTimeUtil.formatTimeByFormat(mt.getUpdateTime(), "yyyy-MM-dd HH:mm:ss"));
			dsr.setType(DicInit.getSystemCode("merchant_transaction", "status", mt.getStatus()));
			dsr.setStatus("S".equals(mt.getStatus())?"SUCCESS":"FAILED");
			dsr.setMtId(mt.getId());
			if("S".equals(mt.getStatus())){
				merchantMutiplyRate = (new BigDecimal(100).subtract(merchantFeeRate)).divide(new BigDecimal(100));
				BigDecimal billingAmt = mt.getTotalAmount().multiply(merchantMutiplyRate);
				billingAmt = billingAmt.setScale(2,RoundingMode.HALF_UP);
				dsr.setCollectionAmount(mt.getTotalAmount());
				dsr.setExpenditureAmount(mt.getTotalAmount());
				dsr.setRefundAmount(new BigDecimal(0));
				dsr.setSettlementAmount(billingAmt);
			}else if("I".equals(mt.getStatus()) || "F".equals(mt.getStatus()) 
				  || "U".equals(mt.getStatus()) || "R".equals(mt.getStatus())
				  || "C".equals(mt.getStatus()) || "D".equals(mt.getStatus())){
				dsr.setCollectionAmount(new BigDecimal(0));
				dsr.setExpenditureAmount(new BigDecimal(0));
				dsr.setRefundAmount(new BigDecimal(0));
				dsr.setSettlementAmount(new BigDecimal(0));
			}else if("E".equals(mt.getStatus())){
				dsr.setCollectionAmount(new BigDecimal(0));
				dsr.setExpenditureAmount(new BigDecimal(0));
				dsr.setRefundAmount(mt.getTotalAmount().negate());
				dsr.setSettlementAmount(mt.getTotalAmount().negate());
			}
			dsr.setCurrency(mt.getMerchant().getDefaultCurrency()); //TODO need add currency to merchant_transaction
			dsr.setRate(merchantFeeRate);
			dsr.setGoodsTitle(BusinessLogicConstants.TRANS_NAME); //TODO need change to get from payment.transName
			dsr.setProduct(BusinessLogicConstants.REPORT_PRODUCT);
			dsr.setStatusCode(mt.getStatus());
			returnList.add(dsr);
		}
		return returnList;
	}
	public List<DailySettlementRecordModel> getDailySettlementRecordsAdmin() {
		return dailySettlementRecordsAdmin;
	}
	public void setDailySettlementRecordsAdmin(List<DailySettlementRecordModel> dailySettlementRecordsAdmin) {
		this.dailySettlementRecordsAdmin = dailySettlementRecordsAdmin;
	}
	public List<DailySettlementRecordModel> getDailySettlementRecordsSingleMerchant() {
		return dailySettlementRecordsSingleMerchant;
	}
	public void setDailySettlementRecordsSingleMerchant(List<DailySettlementRecordModel> dailySettlementRecordsSingleMerchant) {
		this.dailySettlementRecordsSingleMerchant = dailySettlementRecordsSingleMerchant;
	}
	public MerchantBusinessService getMerchantBusinessService() {
		return merchantBusinessService;
	}
	public void setMerchantBusinessService(MerchantBusinessService merchantBusinessService) {
		this.merchantBusinessService = merchantBusinessService;
	}
	
}